using Beaker.OpenCube.Render.Maths;
using Beaker.OpenCube.Render.Shapes;
using System;
using System.Diagnostics.Contracts;
using Beaker.OpenCube.Render.Materials;

namespace Beaker.OpenCube.Render
{
	public sealed class Intersection
	{
		private readonly Scene _scene;
		private readonly IShape _shape;
		private readonly Ray _ray;
		private readonly double _distance;
		private readonly Point3 _hitPoint;
		private readonly Point3 _localHitPoint;
		private readonly Vector3 _normal;
		private readonly IMaterial _material;

		public Intersection( Scene scene, IShape shape, Ray ray, double distance, Vector3 normal, IMaterial material )
			: this( scene, shape, ray, distance, ray.Origin + ray.Direction * distance, normal, material )
		{
		}

		public Intersection( Scene scene, IShape shape, Ray ray, double distance, Point3 hitPoint, Vector3 normal, IMaterial material )
			: this( scene, shape, ray, distance, hitPoint, hitPoint, normal, material )
		{
		}

		public Intersection( Scene scene, IShape shape, Ray ray, double distance, Point3 hitPoint, Point3 localHitPoint, Vector3 normal, IMaterial material )
		{
			Contract.Requires<ArgumentNullException>( ray != null );

			_scene = scene;
			_shape = shape;
			_ray = ray;
			_distance = distance;
			_hitPoint = hitPoint;
			_localHitPoint = localHitPoint;
			_normal = normal;
			_material = material;
		}


		/// <summary>
		/// Gets the scene.
		/// </summary>
		/// <value>
		/// The scene.
		/// </value>
		[Pure]
		public Scene Scene
		{
			get { return _scene; }
		}

		/// <summary>
		/// Gets the shape the ray is intersecting
		/// </summary>
		[Pure]
		public IShape Shape
		{

			get { return _shape; }
		}

		/// <summary>
		/// Gets the ray that intersects the shape
		/// </summary>
		[Pure]
		public Ray Ray
		{

			get { return _ray; }
		}

		/// <summary>
		/// Gets the distance at which the ray intersects the shape (t)
		/// </summary>
		[Pure]
		public double Distance
		{

			get { return _distance; }
		}

		/// <summary>
		/// Gets the intersection point at which the ray intersects the shape (x,y,z)
		/// </summary>
		public Point3 HitPoint
		{
			get { return _hitPoint; }
		}
		
		/// <summary>
		/// Gets the intersection point - in shape local coordinates - at which the ray intersects the shape (u,w,v)
		/// </summary>
		public Point3 LocalHitPoint
		{
			get { return _localHitPoint; }
		}

		/// <summary>
		/// Gets the normal at the given intersection point
		/// </summary>
		public Vector3 Normal
		{
			get { return _normal; }
		}

		/// <summary>
		/// Gets the surface at the given intersection point
		/// </summary>
		public IMaterial Material
		{
			get { return _material; }
		}
	}
}